package com.tony.easymvc.core;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.jdom2.JDOMException;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tony.easymvc.TemplateUtils;
import com.tony.easymvc.core.bean.ConfigModel;
import com.tony.easymvc.core.bean.GeneratorManifest;
import com.tony.easymvc.core.bean.ModuleConfig;
import com.tony.easymvc.core.bean.ModuleModel;
import com.tony.easymvc.core.bean.ProjectContext;
import com.tony.easymvc.core.bean.ProjectModel;
import com.tony.easymvc.core.controller.ControllerGen;
import com.tony.easymvc.mybatis.core.MapperFileScan;
import com.tony.easymvc.mybatis.core.MybatisPlugin;
import com.tony.easymvc.po.OrMapping;
import com.tony.easymvc.po.ProjectBiz;
import com.tony.easymvc.script.Template;
import com.tony.easymvc.script.TemplateImpl;

public class ProjectGenerator {

	private ConfigModel config = new ConfigModel();

	public void perform(ProjectModel project, ProjectContext context) throws IOException, XMLParserException,
			InvalidConfigurationException, SQLException, InterruptedException, JDOMException {
		project.setProjectContext(context);

		setConfig(project);

		generatorParent();
		generatorMapper();
		updateMapper();

		copyPoToApi();

		generatorApi();
		
		copyStaticFile();
		//
		ControllerGen clg = new ControllerGen(config);
		clg.generator();

	}

	private void generatorApi() {
        // TODO Auto-generated method stub
        
    }

    private void copyPoToApi() {
		try {
			POCopyUtil.copy(config);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void copyStaticFile() throws IOException {
		URL url = this.getClass().getClassLoader().getResource("tmpl");
		copyStaticDir(url, "resources");
	}

	private void copyStaticDir(URL url, String path) throws IOException {
		File file = new File(url.getFile() + "/" + path);
		FileUtils.copy(file, new File(config.getWebappPath() + "/" + path));
	}

	private void setConfig(ProjectModel project) {
		String ppath = project.getBasePath() + "/" + project.getArtifactId();
		config.setParentProjectPath(ppath);
		config.setProject(project);
		ModuleBuilder.build(config);

		setPoProjectPath(project);
		// String mpPath = setMapperPath(project);
		//
		// setXmlPath(mpPath);

		// setControllPackage(project);

		setWebappPath();

		setBizServicePackage(project);

		setBizServiceImplPackage(project);

		config.setAnnotationPackage(project.getScanPackage());
		MybatisPlugin.RW_PACKAGE = config.getAnnotationPackage();
	}

	// private String setMapperPath(ProjectModel project) {
	// String mapperPackage = project.getMapperPackage();
	// String mpPath = mapperPackage.replaceAll("\\.", "/");
	//
	// String mapperPath = config.getModules().get(ModuleConfig.DAL).getPath() +
	// DefaultProjectGenerator.SRC_MAIN_JAVA;
	// mapperPath = mapperPath + "/" + mpPath;
	// config.setMapperPath(mapperPath);
	// return mpPath;
	// }
	//
	// private void setXmlPath(String mpPath) {
	// String xmlPath = config.getModules().get(ModuleConfig.DAL).getPath() +
	// DefaultProjectGenerator.resourcesPath;
	// xmlPath = xmlPath + "/" + mpPath;
	// config.setXmlPath(xmlPath);
	// }
	//
	private void setPoProjectPath(ProjectModel project) {
		String poPackage = project.getPoPackage();
		String tmppoPath = poPackage.replaceAll("\\.", "/");

		String poPath = config.getModules().get(ModuleConfig.PO).get(0).getPath()
				+ DefaultProjectGenerator.SRC_MAIN_JAVA;
		poPath = poPath + "/" + tmppoPath;
		config.setPoPath(poPath);
	}
	//
	// private void setControllPackage(ProjectModel project) {
	// String controllPackage = project.getControllerPackage();
	// String conPath = controllPackage.replaceAll("\\.", "/");
	//
	// String controllPath =
	// config.getModules().get(ModuleConfig.CONTROLLER).getPath()
	// + DefaultProjectGenerator.SRC_MAIN_JAVA;
	//
	// controllPath = controllPath + "/" + conPath;
	// config.setControllerPath(controllPath);
	// }

	private void setBizServicePackage(ProjectModel project) {
		String bizServicePackage = project.getScanPackage() + ".biz.service";
		String conPath = bizServicePackage.replaceAll("\\.", "/");

		String tmpPath = config.getModules().get(ModuleConfig.BIZ_COMMON).get(0).getPath()
				+ DefaultProjectGenerator.SRC_MAIN_JAVA;

		tmpPath = tmpPath + "/" + conPath;
		config.setBizServicePath(tmpPath);
	}

	private void setBizServiceImplPackage(ProjectModel project) {
		String bizServicePackage = project.getScanPackage() + ".biz.service.impl";
		String conPath = bizServicePackage.replaceAll("\\.", "/");

		String tmpPath = config.getModules().get(ModuleConfig.BIZ_COMMON).get(0).getPath()
				+ DefaultProjectGenerator.SRC_MAIN_JAVA;

		tmpPath = tmpPath + "/" + conPath;
		config.setBizServiceImplPath(tmpPath);
	}

	private void setWebappPath() {
		String webappPath = config.getModules().get(ModuleConfig.SERVER).get(0).getPath()
				+ DefaultProjectGenerator.WEBAPP_MAIN_JAVA;
		config.setWebappPath(webappPath);
	}

	private void updateMapper() throws IOException, JDOMException {
		MapperFileScan mfs = new MapperFileScan(config);
		List<ProjectBiz> pbizs = config.getProject().getProjectBizs();
		for (int i = 0; i < pbizs.size(); i++) {
			ProjectBiz biz = pbizs.get(i);
			Map<String, List<OrMapping>> mapping = mfs.readMapping(biz);
			biz.setMapping(mapping);
		}
	}

	/**
	 * 生成基础mapper
	 * 
	 * @throws IOException
	 * @throws XMLParserException
	 * @throws InvalidConfigurationException
	 * @throws SQLException
	 * @throws InterruptedException
	 */
	private void generatorMapper()
			throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {

		List<ProjectBiz> pbizs = this.config.getProject().getProjectBizs();

		for (int i = 0; i < pbizs.size(); i++) {
			ProjectBiz pbiz = pbizs.get(i);
			StringReader configReader = createMybatisConfig(pbiz);

			List<String> warnings = new ArrayList<String>();
			boolean overwrite = true;
			ConfigurationParser cp = new ConfigurationParser(warnings);
			Configuration config = cp.parseConfiguration(configReader);
			DefaultShellCallback callback = new DefaultShellCallback(overwrite);
			MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
			myBatisGenerator.generate(null);
		}

	}

	private StringReader createMybatisConfig(ProjectBiz pbiz) throws IOException {
		String tmp = TemplateUtils.loadTempl("tmpl/mybatis/generatorConfig.tmpl");
		Template t = new TemplateImpl("generatorConfig", tmp);
		Map<String, Object> c = Maps.newHashMap();
		c.put("config", config);
		c.put("biz", pbiz);
		String res = t.resolve(c);
		// System.out.println(res);
		StringReader configReader = new StringReader(res);
		return configReader;
	}

	private void generatorParent() throws IOException {
		DefaultProjectGenerator pg = new DefaultProjectGenerator(config, null, null);
		pg.generator();
		//pg.readme();
		ModuleConfig[] mconfigs = ModuleConfig.values();
		for (int i = 0; i < mconfigs.length; i++) {
				
			try {
				for (ModuleModel mm : config.getModules().get(mconfigs[i])) {
					pg = new DefaultProjectGenerator(config, mconfigs[i], mm);
					pg.generator();
				}
			} catch (Exception e) {
				throw new RuntimeException("mconfigs : " + mconfigs[i].name(), e);
			}
		}
	}

}
